/**************	 机器模式   ***************
         b -- 输出寄存器QImode名称,即寄存器中的最低8位:[a-d]l。
         w -- 输出寄存器HImode名称,即寄存器中2个字节的部分,如[a-d]x。

         HImode
             “Half-Integer”模式，表示一个两字节的整数。
         QImode
             “Quarter-Integer”模式，表示一个一字节的整数。
*******************************************/

#ifndef _INCLUDE_IO_H_
#define _INCLUDE_IO_H_
#include "stdint.h"

/* 向端口port写入一个字节*/
static inline void outb(uint16_t port, uint8_t data)
{
  /*********************************************************
   a表示用寄存器al或ax或eax,对端口指定N表示0~255, d表示用dx存储端口号,
   %b0表示对应al,%w1表示对应dx */
  asm volatile("outb %b0, %w1" : : "a"(data), "Nd"(port));
  /******************************************************/
}

/* 将addr处起始的word_cnt个字写入端口port */
static inline void outsw(uint16_t port, const void* addr, uint32_t word_cnt)
{
  /*********************************************************
     +表示此限制即做输入又做输出.
     outsw是把ds:esi处的16位的内容写入port端口, 我们在设置段描述符时,
     已经将ds,es,ss段的选择子都设置为相同的值了,此时不用担心数据错乱。*/
  asm volatile("cld; rep outsw" : "+S"(addr), "+c"(word_cnt) : "d"(port));
  /******************************************************/
}

/* 将从端口port读入的一个字节返回 */
static inline uint8_t inb(uint16_t port)
{
  uint8_t data;
  asm volatile("inb %w1, %b0" : "=a"(data) : "Nd"(port));
  return data;
}

/* 将从端口port读入的word_cnt个字写入addr */
static inline void insw(uint16_t port, void* addr, uint32_t word_cnt)
{
  /******************************************************
     insw是将从端口port处读入的16位内容写入es:edi指向的内存,
     我们在设置段描述符时, 已经将ds,es,ss段的选择子都设置为相同的值了,
     此时不用担心数据错乱。*/
  asm volatile("cld; rep insw"
               : "+D"(addr), "+c"(word_cnt)
               : "d"(port)
               : "memory");
  /******************************************************/
}

#endif

